package com.hsurosy.infrastructure.persistent.repository;

import cn.bugstack.middleware.db.router.strategy.IDBRouterStrategy;
import com.alibaba.fastjson.JSON;
import com.hsurosy.domain.rebate.model.aggregate.BehaviorRebateAggregate;
import com.hsurosy.domain.rebate.model.entity.BehaviorRebateOrderEntity;
import com.hsurosy.domain.rebate.model.entity.TaskEntity;
import com.hsurosy.domain.rebate.model.valobj.BehaviorTypeVO;
import com.hsurosy.domain.rebate.model.valobj.DailyBehaviorRebateVO;
import com.hsurosy.domain.rebate.repository.IBehaviorRebateRepository;
import com.hsurosy.infrastructure.event.EventPublisher;
import com.hsurosy.infrastructure.persistent.dao.IDailyBehaviorRebateDao;
import com.hsurosy.infrastructure.persistent.dao.ITaskDao;
import com.hsurosy.infrastructure.persistent.dao.IUserBehaviorRebateOrderDao;
import com.hsurosy.infrastructure.persistent.po.DailyBehaviorRebate;
import com.hsurosy.infrastructure.persistent.po.Task;
import com.hsurosy.infrastructure.persistent.po.UserBehaviorRebateOrder;
import com.hsurosy.types.enums.ResponseCode;
import com.hsurosy.types.exception.AppException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author Hsu琛君珩
 * @Date 2024-11-17 17:42
 * @Description 行为返利服务仓储实现
 * @Version: v1.0.0
 */
@Slf4j
@Repository
public class BehaviorRebateRepository implements IBehaviorRebateRepository {

    @Resource
    private IDailyBehaviorRebateDao dailyBehaviorRebateDao; // 每日行为返利规则 DAO
    @Resource
    private IUserBehaviorRebateOrderDao userBehaviorRebateOrderDao; // 用户返利订单 DAO
    @Resource
    private ITaskDao taskDao; // 任务表 DAO
    @Resource
    private IDBRouterStrategy dbRouter; // 数据库路由策略
    @Resource
    private TransactionTemplate transactionTemplate; // 编程式事务模板
    @Resource
    private EventPublisher eventPublisher; // 消息发布工具

    /**
     * 查询每日行为返利规则配置
     *
     * @param behaviorTypeVO 行为类型枚举
     * @return 每日返利规则配置的值对象列表
     */
    @Override
    public List<DailyBehaviorRebateVO> queryDailyBehaviorRebateConfig(BehaviorTypeVO behaviorTypeVO) {
        // 查询数据库中的每日返利规则
        List<DailyBehaviorRebate> dailyBehaviorRebates = dailyBehaviorRebateDao.queryDailyBehaviorRebateByBehaviorType(behaviorTypeVO.getCode());
        // 将数据库实体转换为值对象
        List<DailyBehaviorRebateVO> dailyBehaviorRebateVOS = new ArrayList<>(dailyBehaviorRebates.size());
        for (DailyBehaviorRebate dailyBehaviorRebate : dailyBehaviorRebates) {
            dailyBehaviorRebateVOS.add(DailyBehaviorRebateVO.builder()
                    .behaviorType(dailyBehaviorRebate.getBehaviorType())
                    .rebateDesc(dailyBehaviorRebate.getRebateDesc())
                    .rebateType(dailyBehaviorRebate.getRebateType())
                    .rebateConfig(dailyBehaviorRebate.getRebateConfig())
                    .build());
        }
        return dailyBehaviorRebateVOS;
    }

    /**
     * 保存用户返利记录
     *
     * @param userId 用户ID
     * @param behaviorRebateAggregates 返利记录的聚合对象列表
     */
    @Override
    public void saveUserRebateRecord(String userId, List<BehaviorRebateAggregate> behaviorRebateAggregates) {
        try {
            // 设置数据库路由
            dbRouter.doRouter(userId);
            // 启动事务，确保返利记录和任务的持久化原子性
            transactionTemplate.execute(status -> {
                try {
                    // 遍历每个返利聚合对象
                    for (BehaviorRebateAggregate behaviorRebateAggregate : behaviorRebateAggregates) {
                        // 转换用户行为返利订单对象
                        BehaviorRebateOrderEntity behaviorRebateOrderEntity = behaviorRebateAggregate.getBehaviorRebateOrderEntity();
                        UserBehaviorRebateOrder userBehaviorRebateOrder = new UserBehaviorRebateOrder();
                        userBehaviorRebateOrder.setUserId(behaviorRebateOrderEntity.getUserId());
                        userBehaviorRebateOrder.setOrderId(behaviorRebateOrderEntity.getOrderId());
                        userBehaviorRebateOrder.setBehaviorType(behaviorRebateOrderEntity.getBehaviorType());
                        userBehaviorRebateOrder.setRebateDesc(behaviorRebateOrderEntity.getRebateDesc());
                        userBehaviorRebateOrder.setRebateType(behaviorRebateOrderEntity.getRebateType());
                        userBehaviorRebateOrder.setRebateConfig(behaviorRebateOrderEntity.getRebateConfig());
                        userBehaviorRebateOrder.setOutBusinessNo(behaviorRebateOrderEntity.getOutBusinessNo());
                        userBehaviorRebateOrder.setBizId(behaviorRebateOrderEntity.getBizId());
                        userBehaviorRebateOrderDao.insert(userBehaviorRebateOrder);

                        // 转换任务对象
                        TaskEntity taskEntity = behaviorRebateAggregate.getTaskEntity();
                        Task task = new Task();
                        task.setUserId(taskEntity.getUserId());
                        task.setTopic(taskEntity.getTopic());
                        task.setMessageId(taskEntity.getMessageId());
                        task.setMessage(JSON.toJSONString(taskEntity.getMessage()));
                        task.setState(taskEntity.getState().getCode());
                        taskDao.insert(task);
                    }
                    return 1;
                } catch (DuplicateKeyException e) {
                    // 处理唯一键冲突异常，回滚事务
                    status.setRollbackOnly();
                    log.error("写入返利记录，唯一索引冲突 userId: {}", userId, e);
                    throw new AppException(ResponseCode.INDEX_DUP.getCode(), ResponseCode.INDEX_DUP.getInfo());
                }
            });
        } finally {
            // 清理数据库路由
            dbRouter.clear();
        }

        // 在事务外同步发送消息【可选：异步实现更优】
        for (BehaviorRebateAggregate behaviorRebateAggregate : behaviorRebateAggregates) {
            TaskEntity taskEntity = behaviorRebateAggregate.getTaskEntity();
            Task task = new Task();
            task.setUserId(taskEntity.getUserId());
            task.setMessageId(taskEntity.getMessageId());
            try {
                // 发送MQ消息【在事务外执行，如果失败还有任务补偿】
                eventPublisher.publish(taskEntity.getTopic(), taskEntity.getMessage());
                // 更新任务表状态为已完成
                taskDao.updateTaskSendMessageCompleted(task);
            } catch (Exception e) {
                // 发送失败，更新任务表状态为失败
                log.error("写入返利记录，发送MQ消息失败 userID: {} topic: {}", userId, task.getTopic());
                taskDao.updateTaskSendMessageFail(task);
            }
        }
    }

    /**
     * 根据用户ID和外部业务编号查询用户的行为返利订单列表
     *
     * @param userId 用户ID，用于指定查询的用户
     * @param outBusinessNo 外部业务编号，用于唯一标识业务操作
     * @return 返回用户的行为返利订单实体列表
     */
    @Override
    public List<BehaviorRebateOrderEntity> queryOrderByOutBusinessNo(String userId, String outBusinessNo) {
        // 1. 创建请求对象，用于查询条件
        UserBehaviorRebateOrder userBehaviorRebateOrderReq = new UserBehaviorRebateOrder();
        userBehaviorRebateOrderReq.setUserId(userId); // 设置用户ID
        userBehaviorRebateOrderReq.setOutBusinessNo(outBusinessNo); // 设置外部业务编号

        // 2. 查询数据库，获取用户的行为返利订单列表
        List<UserBehaviorRebateOrder> userBehaviorRebateOrderList = userBehaviorRebateOrderDao.queryOrderByOutBusinessNo(userBehaviorRebateOrderReq);

        // 3. 转换查询结果为业务实体列表
        List<BehaviorRebateOrderEntity> behaviorRebateOrderEntities = new ArrayList<>(userBehaviorRebateOrderList.size());
        for (UserBehaviorRebateOrder userBehaviorRebateOrder : userBehaviorRebateOrderList) {
            // 构建行为返利订单实体对象
            BehaviorRebateOrderEntity behaviorRebateOrderEntity = BehaviorRebateOrderEntity.builder()
                    .userId(userBehaviorRebateOrder.getUserId()) // 设置用户ID
                    .orderId(userBehaviorRebateOrder.getOrderId()) // 设置订单ID
                    .behaviorType(userBehaviorRebateOrder.getBehaviorType()) // 设置行为类型
                    .rebateDesc(userBehaviorRebateOrder.getRebateDesc()) // 设置返利描述
                    .rebateType(userBehaviorRebateOrder.getRebateType()) // 设置返利类型
                    .rebateConfig(userBehaviorRebateOrder.getRebateConfig()) // 设置返利配置
                    .outBusinessNo(userBehaviorRebateOrder.getOutBusinessNo()) // 设置外部业务编号
                    .bizId(userBehaviorRebateOrder.getBizId()) // 设置业务ID
                    .build();
            // 添加到返回列表
            behaviorRebateOrderEntities.add(behaviorRebateOrderEntity);
        }

        return behaviorRebateOrderEntities; // 返回结果列表
    }

}
